<?php

declare(strict_types=1);
/**
 * This file is part of MoChat.
 * @link     https://mo.chat
 * @document https://mochat.wiki
 * @contact  group@mo.chat
 * @license  https://github.com/mochat-cloud/mochat/blob/master/LICENSE
 */
namespace MoChat\App\WorkContact\Action\Dashboard\TagGroup;

use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
use GuzzleHttp\Exception\GuzzleException;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\Middleware;
use Hyperf\HttpServer\Annotation\Middlewares;
use Hyperf\HttpServer\Annotation\RequestMapping;
use MoChat\App\Common\Middleware\DashboardAuthMiddleware;
use MoChat\App\WorkContact\Contract\WorkContactTagContract;
use MoChat\App\WorkContact\Contract\WorkContactTagGroupContract;
use MoChat\App\WorkContact\QueueService\Tag\DeleteApply;
use MoChat\App\WorkContact\QueueService\Tag\StoreApply;
use MoChat\App\WorkContact\QueueService\Tag\UpdateApply;
use MoChat\Framework\Action\AbstractAction;
use MoChat\Framework\Constants\ErrorCode;
use MoChat\Framework\Exception\CommonException;
use MoChat\Framework\Request\ValidateSceneTrait;

/**
 * 修改客户标签分组.
 *
 * Class Update
 * @Controller
 */
class Update extends AbstractAction
{
    use ValidateSceneTrait;

    /**
     * @Inject
     * @var WorkContactTagContract
     */
    protected $workContactTagService;

    /**
     * @Inject
     * @var StoreApply
     */
    protected $storeApply;

    /**
     * @Inject
     * @var UpdateApply
     */
    protected $updateApply;

    /**
     * @Inject
     * @var DeleteApply
     */
    protected $deleteApply;

    /**
     * @Inject
     * @var StdoutLoggerInterface
     */
    protected $logger;

    /**
     * @Inject
     * @var WorkContactTagGroupContract
     */
    private $contactTagGroupService;

    /**
     * @Middlewares({
     *     @Middleware(DashboardAuthMiddleware::class)
     * })
     * @RequestMapping(path="/dashboard/workContactTagGroup/update", methods="PUT")
     */
    public function handle()
    {
        $user = user();
        // 判断用户绑定企业信息
        if (! isset($user['corpIds']) || count($user['corpIds']) !== 1) {
            throw new CommonException(ErrorCode::INVALID_PARAMS, '未选择登录企业，不可操作');
        }
        // 接收参数
        $params['groupId'] = (int) $this->request->input('id');
        $params['groupName'] = trim($this->request->input('groupName'));
        $params['isUpdate'] = (int) $this->request->input('isUpdate');
        $params['tags'] = $this->request->input('tags', []);
        $params['deleteTags'] = $this->request->input('deleteTags', []);
        // 验证参数
        $this->validated($params);

        // 空标签判断
        foreach ($params['tags'] as $item) {
            if (empty($item['name'])) {
                throw new CommonException(ErrorCode::INVALID_PARAMS, '标签名不允许为空');
            }
        }
        // 若修改了信息做校验
        if ($params['isUpdate'] === 1) {
            // 查询是否已存在相同分组名称
            $info = $this->contactTagGroupService
                ->getWorkContactTagGroupsByNameId((int) user()['corpIds'][0], $params['groupName'], $params['groupId']);

            if (! empty($info)) {
                throw new CommonException(ErrorCode::SERVER_ERROR, '已存在相同分组名');
            }
        }

        // 数据操作
        Db::beginTransaction();
        try {
            $groupInfo = $this->contactTagGroupService->getWorkContactTagGroupById($params['groupId']);
            // 修改标签组
            if ($params['groupName'] !== $groupInfo['groupName']) {
                $this->contactTagGroupService
                    ->updateWorkContactTagGroupById($params['groupId'], ['group_name' => $params['groupName']]);
                $this->updateApply->handle(['corpId' => $user['corpIds'][0], 'id' => $groupInfo['wxGroupId'], 'name' => $params['groupName'], 'order' => $groupInfo['order']]);
            }
            // 修改标签
            $this->updateTags($params, $groupInfo);
            // 删除标签
            $this->deleteTags($params);
            Db::commit();
        } catch (\Throwable $e) {
            Db::rollBack();
            $this->logger->error(sprintf('%s [%s] %s', '引流链接创建失败', date('Y-m-d H:i:s'), $e->getMessage()));
            $this->logger->error($e->getTraceAsString());
            throw new CommonException(ErrorCode::SERVER_ERROR, $e->getMessage()); // '活动创建失败'
        }
    }

    /**
     * @return string[] 规则
     */
    public function rules(): array
    {
        return [
            'groupId' => 'required|int',
            'groupName' => 'required',
            'isUpdate' => 'required',
        ];
    }

    /**
     * 获取已定义验证规则的错误消息.
     */
    public function messages(): array
    {
        return [
            'groupId.required' => '分组id必传',
            'groupName.required' => '分组名称必传',
            'isUpdate.required' => '是否修改信息必传',
        ];
    }

    /**
     * 标签处理.
     * @throws GuzzleException
     * @throws InvalidConfigException
     */
    private function deleteTags(array $params): array
    {
        if (empty($params['deleteTags'])) {
            return [];
        }
        $tagIds = array_column($params['deleteTags'], 'id');
        $tagInfo = $this->workContactTagService->getWorkContactTagsById($tagIds, ['wx_contact_tag_id', 'contact_tag_group_id']);
        if (empty($tagInfo)) {
            throw new CommonException(ErrorCode::SERVER_ERROR, '查询不到该标签信息');
        }
        $res = $this->workContactTagService->deleteWorkContactTags($tagIds);

        if (! is_int($res)) {
            throw new CommonException(ErrorCode::SERVER_ERROR, '标签删除失败');
        }

        $tagId = [];
        $contactTagGroupIds = [];
        foreach ($tagInfo as &$raw) {
            if ($raw['contactTagGroupId'] !== 0) {
                $tagId[] = $raw['wxContactTagId'];
                $contactTagGroupIds[] = $raw['contactTagGroupId'];
            }
        }
        unset($raw);

        // -----  以下为同步到企业微信 ----

        if (! empty($tagId)) {
            // 删除微信标签
            $deleteParams = [
                'tag_id' => $tagId,
                'group_id' => [],
            ];

            $this->deleteApply->handle($deleteParams, $contactTagGroupIds, $tagIds, user()['corpIds'][0]);
        }

        return [];
    }

    /**
     * 标签处理.
     * @throws GuzzleException
     * @throws InvalidConfigException
     */
    private function updateTags(array $params, array $groupInfo): array
    {
        if (empty($params['tags'])) {
            return [];
        }
        [$createDate, $updateData, $tag] = $this->handleTags($params['groupId'], $params['tags']);
        // 批量创建标签
        if (! empty($createDate)) {
            $this->workContactTagService->createWorkContactTags($createDate);
            // 添加到企业微信 同时同步企业微信标签分组
            $addParams = [
                'group_id' => $groupInfo['wxGroupId'],
                'order' => $groupInfo['order'],
                'tag' => $tag,
            ];
            $this->storeApply->handle($addParams, $params['groupId'], user()['corpIds'][0]);
        }

        // 批量修改标签
        if (! empty($updateData)) {
            $updateIds = array_column($updateData, 'id');
            $updateTags = $this->workContactTagService->getWorkContactTagsById($updateIds);
            $update = [];
            foreach ($updateTags as $item) {
                $update[$item['id']] = $item;
            }

            foreach ($updateData as $v) {
                if (trim($v['name']) !== $update[$v['id']]['name']) {
                    $this->workContactTagService->updateWorkContactTagById($v['id'], ['name' => trim($v['name']), 'order' => $v['order']]);
                    $this->updateApply->handle(['corpId' => user()['corpIds'][0], 'id' => $update[$v['id']]['wxContactTagId'], 'name' => trim($v['name']), 'order' => $v['order']]);
                }
            }
        }

        return [];
    }

    private function handleTags(int $groupId, array $tags): array
    {
        $count = $this->workContactTagService->countWorkContactTagByGroupId($groupId);
        $createDate = [];
        $updateData = [];
        $tag = [];
        foreach ($tags as $item) {
            if (! empty($item['id'])) {
                $updateData[] = $item;
            } else {
                if (! empty($this->workContactTagService->getWorkContactTagByGroupIdName($groupId, trim($item['name'])))) {
                    throw new CommonException(ErrorCode::SERVER_ERROR, '标签名称重复-' . $item['name']);
                }
                ++$count;
                $createDate[] = [
                    'corp_id' => user()['corpIds'][0],
                    'contact_tag_group_id' => $groupId,
                    'name' => trim($item['name']),
                    'order' => $item['order'] ?? $count,
                ];
                $tag[] = [
                    'name' => trim($item['name']),
                    'order' => $item['order'] ?? $count,
                ];
            }
        }
        return [$createDate, $updateData, $tag];
    }
}
